<?php

namespace common\service;

use common\exception\LogicException;
use common\model\AttributeModel;
use common\model\CheckListModel;
use common\model\ProjectCheckListModel;
use common\model\ProjectDelayReviewWorkflowRelationModel;
use common\model\ProjectModel;
use common\model\ProjectStepReviewWorkflowRelationModel;
use common\model\ProjectTemplateModel;
use common\model\ReviewWorkflowModel;
use common\model\StepCategoryModel;
use common\model\StepModel;
use common\model\StepWorkflowModel;
use common\model\UserModel;
use support\ErrorCode;

class ProjectStepReviewWorkflowRelationService
{

    /**
     * 查询审核流匹配数据树
     * @param int $projectId 项目id
     * @param array $workflowFilter 工序流筛选条件
     * @return array
     * @throws \Exception
     */
    public function selectProjectReviewRelationTree(int $projectId, $workflowFilter = [])
    {
        $workflowFilter['project_template_id'] = model(ProjectModel::class)->where(['project_id' => $projectId])->value('project_template_id');
        $workflows = model(StepWorkflowModel::class)->field('id,name,config,"workflow" as type')->where($workflowFilter)->select();
        $stepList = model(StepModel::class)->field('id,name,code,"step" as type')->select();
        $stepList = array_column($stepList, null, 'code');
        $attributeList = model(AttributeModel::class)->select();
        $attributeMap = array_column($attributeList, null, 'code');
        $thirdLevelIndex = 0;

        $projectCheckListList = model(ProjectCheckListModel::class)->field("*,'check_list' as type")->where(['project_id' => $projectId])->select();
        $projectCheckListList = array_group_by($projectCheckListList, 'project_id', 'step_workflow_id', 'step_id');

        $reviewWorkflowList = model(ReviewWorkflowModel::class)->field('id,name,config')->select();
        $reviewWorkflowList = array_map(function ($item) {
            return CommonService::getFormatAttrData(model(ReviewWorkflowModel::class), $item);
        }, $reviewWorkflowList);
        $reviewWorkflowList = array_column($reviewWorkflowList, null, 'id');
        $projectReviewWorkflowRelationList = model(ProjectStepReviewWorkflowRelationModel::class)->where(['project_id' => $projectId])->select();
        $projectReviewWorkflowRelationList = array_group_by($projectReviewWorkflowRelationList, 'project_id', 'step_workflow_id', 'step_id');

        $stepWorkflowService = StepWorkflowService::getInstance();
        foreach ($workflows as &$workflow) {
            $workflow['type'] = 'step_workflow';
            $stepWorkflowId = $workflow['id'];
            $config = json_decode($workflow['config'], true);
            unset($workflow['config']);
            foreach ($config['nodes'] as $nodeList) {
                foreach ($nodeList as $node) {
                    if (!isset($stepList[$node['module_code']])) {
                        // 工序不存在
                        continue;
                    }
                    $tmpStepInfo = $stepList[$node['module_code']];
                    $tmpStepInfo['type'] = 'step';
                    $tmpStepInfo['project_id'] = $projectId;
                    $tmpStepInfo['step_workflow_id'] = $stepWorkflowId;

                    $currentCheckList = $projectCheckListList[$projectId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                    $currentReviewWorkflowList = $projectReviewWorkflowRelationList[$projectId][$stepWorkflowId][$tmpStepInfo['id']] ?? [];
                    $currentReviewWorkflowList = array_column($currentReviewWorkflowList, null, 'attr_str');

                    if (array_key_exists('config', $node) && count($node['config']) > 0) {
                        $currentCheckList = array_group_by($currentCheckList, 'attr_str');
                        foreach ($node['config'] as $rules) {
                            list($res, $attrKeyList) = $stepWorkflowService->getNodeConfigCombinedAttrList($rules);
                            foreach ($res as $attrBind) {
                                $thirdLevelIndex += 1;
                                $str = '';
                                foreach ($attrBind as $attrVK => $attrV) {
                                    $str .= $attributeMap[$attrKeyList[$attrVK]]['name'] . ":" . $attrV . '-';
                                }
                                $str = trim($str, '-');
                                $tmpAttrCombined = ['id' => $thirdLevelIndex, 'project_id' => $projectId, 'step_workflow_id' => $stepWorkflowId, 'step_id' => $tmpStepInfo['id'], 'name' => $str, 'type' => 'attr_combined'];
                                $tmpAttrCombined['children'] = $currentCheckList[$str] ?? [];
                                $tmpAttrCombined['review_workflow'] = null;
                                $reviewWorkflowRelation = $currentReviewWorkflowList[$str] ?? null;
                                if (!empty($reviewWorkflowRelation)) {
                                    $tmpAttrCombined['review_workflow'] = $reviewWorkflowList[$reviewWorkflowRelation['review_workflow_id']] ?? null;
                                }
                                $tmpStepInfo['children'][] = $tmpAttrCombined;
                            }
                        }
                    } else {
                        $tmpStepInfo['review_workflow'] = null;
                        $reviewWorkflowRelation = $currentReviewWorkflowList[''] ?? null;
                        if (!empty($reviewWorkflowRelation)) {
                            $tmpStepInfo['review_workflow'] = $reviewWorkflowList[$reviewWorkflowRelation['review_workflow_id']] ?? null;
                        }
                        $tmpStepInfo['children'] = $currentCheckList;
                    }
                    $workflow['children'][] = $tmpStepInfo;
                }
            }
        }

        return $workflows;
    }

    /**
     * 查询审核流匹配数据树
     * @param int $projectId 项目id
     * @param int $stepWorkflowId
     * @return array
     * @throws \Exception
     */
    public function selectProjectStepWorkflowReviewRelationTree(int $projectId, int $stepWorkflowId)
    {
//        $project = model(ProjectModel::class)->find($projectId);
        $workflow = model(StepWorkflowModel::class)->field('id,name,step_workflow_config as config,"workflow" as type')->find($stepWorkflowId);
        $stepList = model(StepModel::class)->field('id,id as step_id,step_category_id,name,code,"step" as type,"" as attr_str')->select();
        $stepList = array_column($stepList, null, 'code');
        $attributeList = model(AttributeModel::class)->select();
        $attributeMap = array_column($attributeList, null, 'code');
        $thirdLevelIndex = 0;

        // 项目审核节点配置查询
        $projectCheckListList = model(ProjectCheckListModel::class)->field("*,'check_list' as type")->where(['project_id' => $projectId])->select();
        $projectCheckListList = array_map(function ($item) {
            $item['review_role_config'] = explode(',', $item['review_role_config']);
            $item['check_role_nodes'] = [];
            return $item;
        }, $projectCheckListList);
        $projectCheckListList = array_column($projectCheckListList, 'review_role_config', 'check_list_id');

        // 审核节点查询
//        $projectTemplateId = $project['project_template_id'];
        $checkListList = model(CheckListModel::class)->field("*,'check_list' as type")->where(['project_template_id' => 0, 'step_workflow_id' => $stepWorkflowId])->select();
        $checkListList = array_map(function ($item) use (&$projectCheckListList) {
            $projectReviewRoleConfig = $projectCheckListList[$item['id']] ?? null;
            if (!empty($projectReviewRoleConfig)) {
                $tmp = $projectReviewRoleConfig;
            } else {
                $tmp = explode(',', $item['review_role_config']);
            }
            $item['review_role_config'] = array_values(array_filter($tmp, function ($i) {
                return !empty($i);
            }));
            $item['check_role_nodes'] = [];
            return $item;
        }, $checkListList);
        $checkListList = array_group_by($checkListList, 'step_id');

        // 审核流查询
        $reviewWorkflowList = model(ReviewWorkflowModel::class)->field('id,name,config')->select();
        $roleCodes = [];
        $reviewWorkflowList = array_map(function ($item) use (&$roleCodes, &$reviewWorkflowCodeMap) {
            $item = CommonService::getFormatAttrData(model(ReviewWorkflowModel::class), $item);
            $tmpRoleCode = [];
            foreach ($item['config']['nodes']['reviewer'] as $reviewNode) {
                $roleCodes[$reviewNode['role']] = $reviewNode['role'];
                $tmpRoleCode[$reviewNode['role']] = $reviewNode['role'];
            }
            $item['review_role_code_list'] = $tmpRoleCode;
            return $item;
        }, $reviewWorkflowList);
        $roleNameMap = [];
        if (count($roleCodes)) {
            $roleFilter = ['param' => [
                'filter' => [
                    'role.code' => ['-in', array_values($roleCodes)],
                ],
            ]];
            $roleList = teamones_request('teamones-im', 'role/select', $roleFilter)['data']['rows'];
            $roleNameMap = array_column($roleList, 'name', 'code');
        }
        $reviewWorkflowList = array_column($reviewWorkflowList, null, 'id');
        $projectReviewWorkflowRelationList = model(ProjectStepReviewWorkflowRelationModel::class)->where(['project_id' => $projectId, 'step_workflow_id' => $stepWorkflowId])->select();

        $userIdList = [];
        foreach ($projectReviewWorkflowRelationList as &$projectReviewWorkflowRelationItem) {
            $projectReviewWorkflowRelationItem['review_node_config'] = json_decode($projectReviewWorkflowRelationItem['review_node_config'] ?? '{}', true);
            foreach ($projectReviewWorkflowRelationItem['review_node_config'] as $reviewNodeConfig) {
                if (isset($reviewNodeConfig['user_id']) && $reviewNodeConfig['user_id'] > 0) {
                    $userIdList[$reviewNodeConfig['user_id']] = $reviewNodeConfig['user_id'];
                }
            }
        }
        $userList = [];
        if (count($userIdList) > 0) {
            $userList = model(UserModel::class)->where(['id' => ['IN', array_values($userIdList)]])->field('id,name')->select();
            $userList = array_column($userList, null, 'id');
        }
        $projectReviewWorkflowRelationList = array_map(function ($item) use ($userList) {
            foreach ($item['review_node_config'] as &$reviewNodeConfig) {
                if (isset($reviewNodeConfig['user_id']) && $reviewNodeConfig['user_id'] > 0) {
                    $userIdList[$reviewNodeConfig['user_id']] = $reviewNodeConfig['user_id'];
                    $reviewNodeConfig['user_info'] = $userList[$reviewNodeConfig['user_id']] ?? null;
                }
            }
            return $item;
        }, $projectReviewWorkflowRelationList);


        $projectReviewWorkflowRelationList = array_group_by($projectReviewWorkflowRelationList, 'step_id');

        $workflow['type'] = 'step_workflow';
        $stepWorkflowId = $workflow['id'];
        $config = json_decode($workflow['config'], true);
        $workflow['children'] = [];
        unset($workflow['config']);
        if (empty($config['nodes'])) {
            return [];
        }
        foreach ($config['nodes'] as $nodeList) {
            foreach ($nodeList as $node) {
                if (!isset($stepList[$node['module_code']])) {
                    // 工序不存在
                    continue;
                }
                $tmpStepInfo = $stepList[$node['module_code']];
                $tmpStepInfo['type'] = 'step';
                $tmpStepInfo['project_id'] = $projectId;
                $tmpStepInfo['step_workflow_id'] = $stepWorkflowId;

                $currentCheckList = $checkListList[$tmpStepInfo['id']] ?? [];
                $currentReviewWorkflowList = $projectReviewWorkflowRelationList[$tmpStepInfo['id']] ?? [];
                $currentReviewWorkflowList = array_column($currentReviewWorkflowList, null, 'attr_str');

                if (array_key_exists('config', $node) && count($node['config']) > 0) {
                    $currentCheckList = array_group_by($currentCheckList, 'attr_str');
                    foreach ($node['config'] as $rules) {
                        $attrValList = [];
                        foreach ($rules as $rule) {
                            if (!isset($rule['attribute_key']) || !isset($rule['attribute_values'])) {
                                continue;
                            }
                            $attrValList[$rule['attribute_key']] = $rule['attribute_values'];
                        }
                        // 排序 按照固定规则组合
                        ksort($attrValList);

                        // 提前排好顺序的attr keys
                        $attrKeyList = array_keys($attrValList);
                        // 分离出values 进行组合
                        $attrValList = array_values($attrValList);
                        $res = combine_dika($attrValList);
                        foreach ($res as $attrBind) {
                            $thirdLevelIndex += 1;
                            $str = '';
                            foreach ($attrBind as $attrVK => $attrV) {
                                $str .= $attributeMap[$attrKeyList[$attrVK]]['name'] . ":" . $attrV . '-';
                            }
                            $str = trim($str, '-');
                            $tmpAttrCombined = ['id' => $thirdLevelIndex, 'project_id' => $projectId, 'step_workflow_id' => $stepWorkflowId, 'step_category_id' => $tmpStepInfo['step_category_id'], 'step_id' => $tmpStepInfo['id'], 'name' => $str, 'attr_str' => $str, 'type' => 'attr_combined'];
                            $tmpAttrCombined['children'] = $currentCheckList[$str] ?? [];
                            $tmpAttrCombined['review_workflow'] = null;
                            $tmpAttrCombined['review_workflow_relation'] = $currentReviewWorkflowList[$str] ?? null;
                            $tmpAttrCombined['review_workflow_nodes'] = [];
                            if (!empty($tmpAttrCombined['review_workflow_relation'])) {
                                $reviewNodeConfig = $tmpAttrCombined['review_workflow_relation']['review_node_config'] ?? [];
                                $reviewNodeConfig = array_column($reviewNodeConfig, null, 'role_code');
                                $tmpAttrCombined['review_workflow'] = $reviewWorkflowList[$tmpAttrCombined['review_workflow_relation']['review_workflow_id']] ?? null;
                                if (!empty($tmpAttrCombined['review_workflow'])) {
                                    foreach ($tmpAttrCombined['review_workflow']['config']['nodes']['reviewer'] as $reviewNode) {
                                        $tmpAttrCombined['review_workflow_nodes'][] = [
                                            'role_code' => $reviewNode['role'],
                                            'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                            'user_id' => $reviewNodeConfig[$reviewNode['role']]['user_id'] ?? 0,
                                            'user_info' => $reviewNodeConfig[$reviewNode['role']]['user_info'] ?? null,
                                        ];
                                        foreach ($tmpAttrCombined['children'] as &$currentAttrCheckList) {
                                            if (empty($currentAttrCheckList['review_role_config'])) {
                                                $currentAttrCheckList['review_role_config'] = $tmpAttrCombined['review_workflow']['review_role_code_list'];
                                            }
                                            $currentAttrCheckList['check_role_nodes'][] = [
                                                'role_code' => $reviewNode['role'],
                                                'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                                'is_check' => in_array($reviewNode['role'], $currentAttrCheckList['review_role_config']) || empty($currentAttrCheckList['review_role_config'])
                                            ];
                                        }
                                    }
                                }
                            }
                            $tmpStepInfo['children'][] = $tmpAttrCombined;
                        }
                    }
                } else {
                    $tmpStepInfo['children'] = $currentCheckList;
                    $tmpStepInfo['review_workflow'] = null;
                    $tmpStepInfo['review_workflow_relation'] = $currentReviewWorkflowList[''] ?? null;
                    $tmpStepInfo['review_workflow_nodes'] = [];
                    if (!empty($tmpStepInfo['review_workflow_relation'])) {
                        $reviewNodeConfig = $tmpStepInfo['review_workflow_relation']['review_node_config'] ?? [];
                        $reviewNodeConfig = array_column($reviewNodeConfig, null, 'role_code');
                        $tmpStepInfo['review_workflow'] = $reviewWorkflowList[$tmpStepInfo['review_workflow_relation']['review_workflow_id']] ?? null;
                        if (!empty($tmpStepInfo['review_workflow'])) {
                            foreach ($tmpStepInfo['review_workflow']['config']['nodes']['reviewer'] as $reviewNode) {
                                $tmpStepInfo['review_workflow_nodes'][] = [
                                    'role_code' => $reviewNode['role'],
                                    'role_cname' => $roleNameMap[$reviewNode['role']] ?? '未知',
                                    'user_id' => $reviewNodeConfig[$reviewNode['role']]['user_id'] ?? 0,
                                    'user_info' => $reviewNodeConfig[$reviewNode['role']]['user_info'] ?? null,
                                ];
                                foreach ($tmpStepInfo['children'] as &$currentStepCheckList) {
                                    $currentStepCheckList['check_role_nodes'][] = [
                                        'role_code' => $reviewNode['role'],
                                        'role_cname' => $roleNameMap[$reviewNode['role']] ?? 'unknown',
                                        'is_check' => in_array($reviewNode['role'], $currentStepCheckList['review_role_config']) || empty($currentStepCheckList['review_role_config'])
                                    ];
                                }
                            }
                        }
                    }
                }
                $workflow['children'][] = $tmpStepInfo;
            }
        }

        return $workflow['children'];
    }


    /**
     * 保存关联关系
     * @param array $relationData
     * @return array|bool
     * @throws \Exception
     */
    public function saveRelation(array $relationData)
    {
        $where = [
            'project_id' => $relationData['project_id'],
            'step_workflow_id' => $relationData['step_workflow_id'],
            'step_id' => $relationData['step_id'],
            'attr_str' => $relationData['attr_str'],
        ];
        $existData = model(ProjectStepReviewWorkflowRelationModel::class)->where($where)->find();
        if (!empty($existData)) {
            $relationData['id'] = $existData['id'];
            $res = model(ProjectStepReviewWorkflowRelationModel::class)->modifyItem($relationData);
        } else {
            $res = model(ProjectStepReviewWorkflowRelationModel::class)->addItem($relationData);
        }
        return $res;
    }

    /**
     * 批量设置工序流
     * @param array $relationDataList
     * @param int $projectId
     * @return array
     * @throws \Exception
     */
    public function saveProjectReviewRelation(array $relationDataList, int $projectId)
    {
        $where = [
            '_logic' => 'or',
        ];
        $checklistFilter = [
            '_logic' => 'or',
        ];
        $sourceStepWorkflowIdList = array_column($relationDataList, 'step_workflow_id');
        $projectStepWorkflowList = model(StepWorkflowModel::class)
            ->where([
                'project_id' => $projectId,
                'is_enable' => 'yes',
                'source_id' => ['in', implode(',', $sourceStepWorkflowIdList)]
            ])
            ->field('id, source_id')
            ->select();
        $projectStepWorkflowMap = array_column($projectStepWorkflowList, 'id', 'source_id');
        // map到项目级工序流
        $projectTemplateId = model(ProjectModel::class)->where(['id' => $projectId])->getField('project_template_id');
        foreach ($relationDataList as $relationData) {
            $where[] = [
                'project_id' => $relationData['project_id'],
                'step_workflow_id' => $relationData['step_workflow_id'],
                'step_id' => $relationData['step_id'],
                'attr_str' => $relationData['attr_str'],
            ];
            // 保留老工序流兼容
            $checklistFilter[] = [
                'project_template_id' => ['in', $projectTemplateId . ',0'],
                'step_workflow_id' => $relationData['step_workflow_id'],
                'step_id' => $relationData['step_id'],
                'attr_str' => $relationData['attr_str'],
            ];
            if (isset($projectStepWorkflowMap[$relationData['step_workflow_id']])) {
                // 项目级工序流启用了，查项目工序流的check_list
                $checklistFilter[] = [
                    'project_template_id' => 0,
                    'step_workflow_id' => $projectStepWorkflowMap[$relationData['step_workflow_id']],
                    'step_id' => $relationData['step_id'],
                    'attr_str' => $relationData['attr_str'],
                ];
            }
        }
        $existDataList = model(ProjectStepReviewWorkflowRelationModel::class)->where($where)->select();
        $existDataList = array_index_by($existDataList, '_', 'project_id', 'step_workflow_id', 'step_id', 'attr_str');


        $checkList = model(CheckListModel::class)->where($checklistFilter)->select();
        $checkList = array_group_by($checkList, 'step_workflow_id', 'step_id', 'attr_str');

        $relationDataList = array_index_by($relationDataList, '_', 'project_id', 'step_workflow_id', 'step_id', 'attr_str');

        $reviewWorkflowList = model(ReviewWorkflowModel::class)->where(['id' => ['IN', array_unique(array_column($relationDataList, 'review_workflow_id'))]])->field("id,JSON_UNQUOTE(JSON_EXTRACT(config,'$.nodes.reviewer')) as reviewer_config")->select();
        $reviewWorkflowList = array_map(function ($item) {
            $item['config'] = json_decode($item['reviewer_config'], true);
            $item['reviewer_codes'] = implode(',', array_column($item['config'], 'role'));
            return $item;
        }, $reviewWorkflowList);
        $reviewWorkflowList = array_column($reviewWorkflowList, 'reviewer_codes', 'id');

        $addDataList = [];
        $res = [];
        $res['relation_updated'] = 0;

        $projectMemberInsertData = [];
        $saveCheckListData = [];
        $saveProjectCheckListData = [];
        $updateProjectCheckListCodeData = [];
        foreach ($relationDataList as $key => $relationData) {
            $existData = $existDataList[$key] ?? 0;
            if (isset($relationData['review_node_config'])) {
                foreach ($relationData['review_node_config'] as $relationDatum) {
                    if (isset($relationDatum['user_id']) && isset($relationDatum['role_code'])) {
                        $projectMemberInsertData[$relationDatum['user_id'] . $relationDatum['role_code']] = $relationDatum;
                    }
                }
                $relationData['review_node_config'] = json_encode($relationData['review_node_config']);
            }
            if (!empty($existData)) {
                $res['relation_updated'] += model(ProjectStepReviewWorkflowRelationModel::class)->where(['id' => $existData['id']])->save($relationData);

            } else {
                $relationData['uuid'] = create_uuid();
                $addDataList[] = $relationData;
            }

            $existCheckList = $checkList[$relationData['step_workflow_id']][$relationData['step_id']][$relationData['attr_str']] ?? [];
            // 检查项目check_list是否存在，如果不存在，需要先创建check_list
            $realStepWorkFlowId = $projectStepWorkflowMap[$relationData['step_workflow_id']] ?? 0;

            $existCheckListRealMap = [];
            foreach ($checkList[$realStepWorkFlowId][$relationData['step_id']][$relationData['attr_str']] ?? [] as $item) {
                $mapKey = $item['step_id']
                    . '#' . $item['content'];
                $existCheckListRealMap[$mapKey] = $item;
            }
            foreach ($existCheckList as $item) {
                // 通过工序流、工序、节点找到对应的check_list_id
                // 如果不存在则添加
                $realCheckListKey = $item['step_id']
                    . '#' . $item['content'];
                // 如果项目工序流不在启用列表，则不创建
                if (isset($projectStepWorkflowMap[$item['step_workflow_id']]) && !isset($existCheckListRealMap[$realCheckListKey])) {
                    $saveTemp = $item;
                    unset($saveTemp['id']);
                    $saveTemp['uuid'] = create_uuid();
                    $saveTemp['project_template_id'] = 0;
                    $saveTemp['step_workflow_id'] = $projectStepWorkflowMap[$saveTemp['step_workflow_id']];
                    $saveCheckListData[] = $saveTemp;
                    $saveProjectCheckListData[] = [
                        'check_list_uuid' => $saveTemp['uuid'],
                        'project_id' => $projectId,
                        'review_role_config' => $reviewWorkflowList[$relationData['review_workflow_id']],
                    ];
                }
            }
            // 随后处理check_list内的更新
            // 更新已有check_list节点配置的角色信息
            if (count($existCheckList) > 0) {
                $checkListIdList = array_column($existCheckList, 'id');
                if (!isset($updateProjectCheckListCodeData[$relationData['review_workflow_id']])) {
                    $reviewCodes = $reviewWorkflowList[$relationData['review_workflow_id']];
                    foreach ($checkListIdList as $checkListId) {
                        $updateProjectCheckListCodeData[] = [
                            'id' => $checkListId,
                            'review_role_config' => $reviewCodes
                        ];
                    }
                }
            }
        }
        if (!empty($saveCheckListData)) {
            $res['check_list_add'] = $this->addCheckListRoleCode($saveCheckListData, $saveProjectCheckListData);
        }
        $res['check_list'] = 0;
        if (count($updateProjectCheckListCodeData) > 0) {
            $res['check_list'] = $this->saveCheckListRoleCode($updateProjectCheckListCodeData, $projectId);
        }

        if (count($addDataList) > 0) {
            $res['relation_added'] = model(ProjectStepReviewWorkflowRelationModel::class)->addAll($addDataList);
        }
        if (count($projectMemberInsertData) > 0) {
            $projectService = ProjectService::getInstance();
            $data = [
                'user_list' => array_values($projectMemberInsertData),
                'project_id' => $projectId,
            ];
            $projectService->batchCreateProjectMemberMultiRole($data);
        }
        return $res;
    }

    /**
     * 查询延期审核流配置
     * @param $filter
     * @return array
     * @throws \Exception
     */
    public function selectDelayReviewRelation($filter)
    {
        $res = [];
        $projectId = intval($filter['project_id']);
        $delayReviewRelationList = model(ProjectDelayReviewWorkflowRelationModel::class)->where($filter)->select();
        $templateWorkflowList = $this->getReviewWorkflowFromProjectTemplate($projectId);

        // 非单条查询时，补全系统配置
        if (!isset($filter['step_category_id']) && !isset($filter['id'])) {
            $noRelationStepCategoryIdList = array_diff(
                array_column($templateWorkflowList, 'id'),
                array_column($delayReviewRelationList, 'step_category_id')
            );
            $delayReviewRelationList = array_merge(
                $delayReviewRelationList,
                array_map(function ($item) use ($projectId) {
                    return [
                        'project_id' => $projectId,
                        'step_category_id' => $item,
                        'review_workflow_id' => null,
                        'review_node_config' => [],
                    ];
                }, $noRelationStepCategoryIdList)
            );
        }

        $reviewWorkflowIdList = array_unique(
            array_filter(
                array_column($delayReviewRelationList, 'review_workflow_id'),
                function ($item) {
                    return !empty($item);
                }
            )
        );
        $reviewWorkflowMap = [];
        if (!empty($reviewWorkflowIdList)) {
            $reviewWorkflowMap = model(ReviewWorkflowModel::class)
                ->where(['id' => ['IN', $reviewWorkflowIdList]])
                ->select();
            $reviewWorkflowMap = array_column($reviewWorkflowMap, null, 'id');
        }

        $stepCategoryIdList = array_unique(
            array_filter(
                array_column($delayReviewRelationList, 'step_category_id'),
                function ($item) {
                    return !empty($item);
                }
            )
        );
        $stepCategoryMap = [];
        if (!empty($stepCategoryIdList)) {
            $stepCategoryMap = model(StepCategoryModel::class)
                ->where(['id' => ['IN', $stepCategoryIdList]])
                ->field('id, name, code')
                ->select();
            $stepCategoryMap = array_column($stepCategoryMap, null, 'id');
        }


        foreach ($delayReviewRelationList as $delayReviewRelation) {
            $row = [
                'project_id' => $delayReviewRelation['project_id'],
                'show_name' => $templateWorkflowList[$delayReviewRelation['step_category_id']]['show_name'] ?? '',
                'type' => 'project',
                'step_category_id' => $delayReviewRelation['step_category_id'],
                'review_workflow_id' => 0
            ];

            if (isset($stepCategoryMap[$delayReviewRelation['step_category_id']])) {
                $stepCategory = $stepCategoryMap[$delayReviewRelation['step_category_id']];
                $row['name'] = $stepCategory['name'];
                $row['code'] = $stepCategory['code'];
            }

            $nodeConfig = [];
            if (empty($delayReviewRelation) || empty($delayReviewRelation['review_workflow_id'])) {
                $row['type'] = 'system';
                $row['review_workflow_id'] = $templateWorkflowList[$delayReviewRelation['step_category_id']]['delay_order_task_review_workflow_id'] ?? 0;

            } else {
                $nodeConfig = json_decode($delayReviewRelation['review_node_config'] ?? '', true);
                $row['review_workflow_id'] = $delayReviewRelation['review_workflow_id'];
            }

            if (!empty($row['review_workflow_id']) && isset($reviewWorkflowMap[$row['review_workflow_id']])) {
                $reviewWorkflow = $reviewWorkflowMap[$row['review_workflow_id']];
                $reviewWorkflowConfig = json_decode($reviewWorkflow['config'], true);
                $roleCodes = array_column($reviewWorkflowConfig['nodes']['reviewer'], 'role');
                $roleNameMap = [];
                if (count($roleCodes)) {
                    $roleFilter = ['param' => [
                        'filter' => [
                            'role.code' => ['-in', array_values($roleCodes)],
                        ],
                    ]];
                    $roleList = teamones_request('teamones-im', 'role/select', $roleFilter)['data']['rows'];
                    $roleNameMap = array_column($roleList, 'name', 'code');
                }

                $userIdList = array_unique(array_column($nodeConfig, 'user_id'));
                $userList = [];
                if (count($userIdList) > 0) {
                    $userList = model(UserModel::class)->where(['id' => ['IN', array_values($userIdList)]])->field('id,name')->select();
                    $userList = array_column($userList, null, 'id');
                }

                $nodeConfigMap = array_column($nodeConfig, null, 'role_code');
                foreach ($reviewWorkflowConfig ['nodes']['reviewer'] as $item) {
                    $node = [
                        'role_name' => $roleNameMap[$item['role']] ?? '',
                        'role_code' => $item['role'],
                    ];
                    if (isset($nodeConfigMap[$item['role']]) && !empty($nodeConfigMap[$item['role']]['user_id'])) {
                        $node['user_id'] = $nodeConfigMap[$item['role']]['user_id'];
                        $node['user_info'] = $userList[$node['user_id']] ?? [];
                    }
                    $row['review_workflow_nodes'][] = $node;
                }
            }
            $res[] = $row;
        }
        return $res;
    }

    /**
     * 从模板获取延期审核流ID
     * @param $projectId
     * @param $stepCategoryId
     * @return int|mixed
     */
    private function getReviewWorkflowFromProjectTemplate($projectId)
    {
        if (empty($projectId)) {
            return [];
        }
        $projectTemplateConfig = model(ProjectModel::class)
            ->join('project_template on project_template.id = project.project_template_id')
            ->where(['project.id' => $projectId])
            ->getField('project_template.config');
        $producerStepCategoryConfig = json_decode($projectTemplateConfig ?? '', true)['producer_step_category_config'] ?? [];
        return array_map(function ($item) {
            $item['delay_order_task_review_workflow_id'] = intval($item['delay_order_task_review_workflow_id'] ?? 0);
            return $item;
        }, array_column($producerStepCategoryConfig, null, 'id'));
    }

    /**
     * 设置延期审核流
     * @param $relationDataList
     * @param $projectId
     * @return bool|float|int|string
     * @throws \Exception
     */
    public function saveProjectDelayReviewRelation(array $data)
    {
        $projectDelayReviewWorkflowRelationModel = model(ProjectDelayReviewWorkflowRelationModel::class);
        $data['review_node_config'] = json_encode($data['review_node_config'] ?? []);

        $where = [];
        foreach (['id', 'step_category_id', 'project_id', 'attr_str'] as $item) {
            if (!empty($data[$item] ?? [])) {
                $where[$item] = $data[$item];
            }
        }
        $existData = $projectDelayReviewWorkflowRelationModel->where($where)->find();

        if (empty($data['review_workflow_id'] ?? 0)) {
            $templateWorkflowList = $this->getReviewWorkflowFromProjectTemplate($data['project_id']);
            $data['review_workflow_id'] = $templateWorkflowList[$data['step_category_id']]['delay_order_task_review_workflow_id'] ?? 0;
            $data['review_node_config'] = '[]';
        }

        if (!empty($existData)) {
            $data['id'] = $existData['id'];
            return $projectDelayReviewWorkflowRelationModel->save($data);
        } else {
            if (empty($data['project_id'] ?? [])) {
                throw new LogicException('no project id defined', ErrorCode::PROJECT_NOT_FOUND);
            }
            unset($data['id']);
            return $projectDelayReviewWorkflowRelationModel->add($data);
        }
    }

    /**
     * 保存审核点审核角色code数据
     * @param $dataList
     * @param int $projectId
     * @return bool|int|string
     * @throws \Exception
     */
    public function saveCheckListRoleCode($dataList, int $projectId)
    {
        $res = 0;
        $dataListGrouped = array_group_by($dataList, 'review_role_config');
        foreach ($dataListGrouped as $reviewRoleConfig => $dataList) {
            // TODO 循环里面做了DB操作，要控制dataList 数据量

            $checklistIdList = array_column($dataList, 'id');

            $projectChecklistList = model(ProjectCheckListModel::class)->where(['project_id' => $projectId, 'check_list_id' => ['IN', $checklistIdList]])->select();
            $existCheckListIdList = [];
            if (count($projectChecklistList) > 0) {
                $existCheckListIdList = array_column($projectChecklistList, 'check_list_id');
                $res += model(ProjectCheckListModel::class)->where(['id' => ['IN', array_column($projectChecklistList, 'id')]])->save(['review_role_config' => $reviewRoleConfig]);
            }
            $needAdd = [];
            foreach ($checklistIdList as $checklistId) {
                if (!in_array($checklistId, $existCheckListIdList)) {
                    $needAdd[] = [
                        'project_id' => $projectId,
                        'check_list_id' => $checklistId,
                        'review_role_config' => $reviewRoleConfig,
                        'uuid' => create_uuid(),
                    ];
                }
            }
            if (count($needAdd) > 0) {
                model(ProjectCheckListModel::class)->addAll($needAdd);
            }
        }
        return $res;
    }

    /**
     * 保存不存在的审核点审核角色code数据
     * @param     $dataList
     * @param int $projectId
     * @return bool|int|string
     * @throws \Exception
     */
    public function addCheckListRoleCode($saveCheckList, $saveProjectCheckList)
    {
        $res = 0;
        // 先保存checkList
        $checkListRes = model(CheckListModel::class)->addAll($saveCheckList);
        $saveCheckListData = model(CheckListModel::class)
            ->where(['id' => ['in', $checkListRes]])
            ->field('id,uuid')
            ->select();
        $checkListMap = array_column($saveCheckListData, 'id', 'uuid');
        $saveProjectCheckListData = [];
        foreach ($saveProjectCheckList as $item) {
            if (isset($checkListMap[$item['check_list_uuid']])) {
                $item['check_list_id'] = $checkListMap[$item['check_list_uuid']];
                unset($item['check_list_uuid']);
                $saveProjectCheckListData[] = $item;
            }
        }
//        $checkListRes = model(CheckListModel::class)->addAll($saveCheckList);
        return $res;
    }
}
